package com.answeringplayer.service.Impl;

import com.answeringplayer.domain.Category;
import com.answeringplayer.domain.Question;
import com.answeringplayer.domain.QuestionBank;
import com.answeringplayer.dto.*;
import com.answeringplayer.mapper.CategoryMapper;
import com.answeringplayer.mapper.PracticeRecordMapper;
import com.answeringplayer.mapper.QuestionBankMapper;
import com.answeringplayer.mapper.QuestionMapper;
import com.answeringplayer.service.QueryService;
import com.answeringplayer.service.QuestionService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class QuestionServiceImpl implements QuestionService {

    private final CategoryMapper categoryMapper;
    private final QuestionBankMapper questionBankMapper;
    private final QuestionMapper questionMapper;
    private final PracticeRecordMapper practiceRecordMapper;

    @Override
    public List<CategoryDTO> getAllCategories() {
        List<Category> categories = categoryMapper.selectAll();
        Map<Integer, Integer> bankCountMap = getBankCountMap();

        return categories.stream().map(category -> {
            CategoryDTO dto = new CategoryDTO();
            dto.setCategoryId(category.getCategoryId());
            dto.setName(category.getName());
            dto.setSortOrder(category.getSortOrder());
            dto.setCreatedAt(category.getCreatedAt().toLocalDateTime());
            dto.setQuestionBankCount(bankCountMap.getOrDefault(category.getCategoryId(), 0));
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public CategoryDTO getCategoryById(Integer categoryId) {
        Category category = categoryMapper.selectById(categoryId);
        if (category == null) {
            return null;
        }

        Map<Integer, Integer> bankCountMap = getBankCountMap();
        CategoryDTO dto = new CategoryDTO();
        dto.setCategoryId(category.getCategoryId());
        dto.setName(category.getName());
        dto.setSortOrder(category.getSortOrder());
        dto.setCreatedAt(category.getCreatedAt().toLocalDateTime());
        dto.setQuestionBankCount(bankCountMap.getOrDefault(categoryId, 0));

        return dto;
    }

    @Override
    public List<QuestionBankDTO> getAllQuestionBanks() {
        List<QuestionBank> banks = questionBankMapper.selectAll();
        return banks.stream().map(this::convertToQuestionBankDTO).collect(Collectors.toList());
    }

    @Override
    public List<QuestionBankDTO> getQuestionBanksByCategory(Integer categoryId) {
        List<QuestionBank> banks = questionBankMapper.selectByCategoryId(categoryId);
        return banks.stream().map(this::convertToQuestionBankDTO).collect(Collectors.toList());
    }

    @Override
    public QuestionBankDTO getQuestionBankDetail(Integer bankId) {
        QuestionBank bank = questionBankMapper.selectById(bankId);
        if (bank == null) {
            return null;
        }

        // 直接返回包含统计信息的 QuestionBankDTO
        return convertToQuestionBankDTOWithStatistics(bank);
    }

    @Override
    public List<QuestionBankDTO> getQuestionBanksByPage(Integer categoryId, String keyword, Integer page, Integer pageSize) {
        int offset = (page - 1) * pageSize;
        List<QuestionBank> banks = questionBankMapper.selectPage(categoryId, keyword, offset, pageSize);
        return banks.stream().map(this::convertToQuestionBankDTO).collect(Collectors.toList());
    }

    @Override
    public List<QuestionDTO> getQuestionsByBank(Integer bankId) {
        List<Question> questions = questionMapper.selectByBankId(bankId);
        return questions.stream().map(this::convertToQuestionDTO).collect(Collectors.toList());
    }

    @Override
    public QuestionDTO getQuestionDetail(Long questionId) {
        Question question = questionMapper.selectById(questionId);
        if (question == null) {
            return null;
        }

        // 直接返回 QuestionDTO，其中已包含详细信息
        return convertToQuestionDTO(question);
    }

    @Override
    public List<QuestionDTO> getQuestionsByPage(Integer bankId, String questionType, Integer difficulty, Integer page, Integer pageSize) {
        int offset = (page - 1) * pageSize;
        List<Question> questions = questionMapper.selectPage(bankId, questionType, difficulty, offset, pageSize);
        return questions.stream().map(this::convertToQuestionDTO).collect(Collectors.toList());
    }

    @Override
    public List<PracticeRecordDTO> queryPracticeRecord(Long userId) {
        return practiceRecordMapper.selectByUserId(userId);
    }

    // 私有辅助方法
    private Map<Integer, Integer> getBankCountMap() {
        return questionBankMapper.countByCategory().stream()
                .collect(Collectors.toMap(
                        map -> (Integer) map.get("category_id"),
                        map -> ((Long) map.get("count")).intValue()
                ));
    }

    private QuestionBankDTO convertToQuestionBankDTO(QuestionBank bank) {
        QuestionBankDTO dto = new QuestionBankDTO();
        dto.setBankId(bank.getBankId());
        dto.setCategoryId(bank.getCategoryId());
        dto.setName(bank.getName());
        dto.setDescription(bank.getDescription());
        dto.setCreatedAt(bank.getCreatedAt().toLocalDateTime());
        dto.setUpdatedAt(bank.getUpdatedAt().toLocalDateTime());

        // 基础版本不包含统计信息
        return dto;
    }

    private QuestionBankDTO convertToQuestionBankDTOWithStatistics(QuestionBank bank) {
        QuestionBankDTO dto = new QuestionBankDTO();
        dto.setBankId(bank.getBankId());
        dto.setCategoryId(bank.getCategoryId());
        dto.setName(bank.getName());
        dto.setDescription(bank.getDescription());
        dto.setCreatedAt(bank.getCreatedAt().toLocalDateTime());
        dto.setUpdatedAt(bank.getUpdatedAt().toLocalDateTime());

        // 添加统计信息
        Map<String, Object> statistics = calculateBankStatistics(bank.getBankId());
        dto.setTotalQuestions((Integer) statistics.get("totalQuestions"));
        dto.setSingleChoiceCount((Integer) statistics.get("singleChoiceCount"));
        dto.setMultipleChoiceCount((Integer) statistics.get("multipleChoiceCount"));
        dto.setTrueFalseCount((Integer) statistics.get("trueFalseCount"));
        dto.setFillInCount((Integer) statistics.get("fillInCount"));
        dto.setAvgDifficulty((Double) statistics.get("avgDifficulty"));

        return dto;
    }

    private QuestionDTO convertToQuestionDTO(Question question) {
        QuestionDTO dto = new QuestionDTO();
        dto.setQuestionId(question.getQuestionId());
        dto.setBankId(question.getBankId());
        dto.setQuestionType(question.getQuestionType());
        dto.setQuestionTypeText(getQuestionTypeText(question.getQuestionType()));
        dto.setContent(question.getContent());
        dto.setCorrectAnswer(question.getCorrectAnswer());
        dto.setAnalysis(question.getAnalysis());
        dto.setDifficulty(question.getDifficulty());
        dto.setDifficultyText(getDifficultyText(question.getDifficulty()));
        dto.setCreatedAt(question.getCreatedAt().toLocalDateTime());
        dto.setUpdatedAt(question.getUpdatedAt().toLocalDateTime());

        QuestionBank bank = questionBankMapper.selectById(question.getBankId());
        if (bank != null) {
            dto.setBankName(bank.getName());
            dto.setCategoryId(bank.getCategoryId());
        }

        return dto;
    }

    private Map<String, Object> calculateBankStatistics(Integer bankId) {
        List<Question> questions = questionMapper.selectByBankId(bankId);

        int totalQuestions = questions.size();
        int singleChoiceCount = (int) questions.stream()
                .filter(q -> "SINGLE".equals(q.getQuestionType())).count();
        int multipleChoiceCount = (int) questions.stream()
                .filter(q -> "MULTIPLE".equals(q.getQuestionType())).count();
        int trueFalseCount = (int) questions.stream()
                .filter(q -> "TRUE_FALSE".equals(q.getQuestionType())).count();
        int fillInCount = (int) questions.stream()
                .filter(q -> "FILL_IN".equals(q.getQuestionType())).count();

        double avgDifficulty = questions.stream()
                .mapToInt(Question::getDifficulty)
                .average()
                .orElse(3.0);
        avgDifficulty = Math.round(avgDifficulty * 10.0) / 10.0;

        return Map.of(
                "totalQuestions", totalQuestions,
                "singleChoiceCount", singleChoiceCount,
                "multipleChoiceCount", multipleChoiceCount,
                "trueFalseCount", trueFalseCount,
                "fillInCount", fillInCount,
                "avgDifficulty", avgDifficulty
        );
    }

    private String getQuestionTypeText(String questionType) {
        switch (questionType) {
            case "SINGLE": return "单选题";
            case "MULTIPLE": return "多选题";
            case "TRUE_FALSE": return "判断题";
            case "FILL_IN": return "填空题";
            default: return "未知题型";
        }
    }

    private String getDifficultyText(Integer difficulty) {
        switch (difficulty) {
            case 1: return "非常简单";
            case 2: return "简单";
            case 3: return "中等";
            case 4: return "困难";
            case 5: return "非常困难";
            default: return "未知难度";
        }
    }
}